package com.koron.device.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.koron.bean.base.Response;
import com.koron.bean.system.post.query.PostUserQuery;
import com.koron.bean.system.post.vo.PostUserVo;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.common.core.business.system.feign.SystemFeignService;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.message.MessageUtil;
import com.koron.common.task.web.entity.CronTask;
import com.koron.common.task.web.mapper.CronTaskMapper;
import com.koron.common.task.web.service.XxlJobService;
import com.koron.device.bean.po.EquipmentMaintainPo;
import com.koron.device.bean.po.MaintainDetailDto;
import com.koron.device.bean.po.MaintainEquipmentPo;
import com.koron.device.feign.OrderFeignService;
import com.koron.device.mapper.EquipmentMaintainMapper;
import com.koron.device.service.EquipmentMaintainService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
@Slf4j
public class EquipmentMaintainServiceImpl implements EquipmentMaintainService {

    @Autowired
    XxlJobService xxlJobService;

    @Autowired
    OrderFeignService orderFeignService;

    @Autowired
    SystemFeignService systemFeignService;

    @Autowired
    MessageUtil messageUtil;

    private void setCurrDs(String mark) {
        ThreadLocalContext.get().setCurrDs(mark);
    }

    public String getCurrDs() {
        return ThreadLocalContext.get().getCurrDs();
    }

    public EamUser getCurrUser() {
        return ThreadLocalContext.get();
    }

    @TaskAnnotation("save")
    @Override
    public Response save(SessionFactory sessionFactory, EquipmentMaintainPo equipmentMaintainPo) {
        EquipmentMaintainMapper maintainMapper = sessionFactory.getMapper(EquipmentMaintainMapper.class);

        Assert.notNull(equipmentMaintainPo, "equipmentMaintainPo 对象不能为空！");

        Integer flag = equipmentMaintainPo.getFlag();
        if (StrUtil.isBlank(equipmentMaintainPo.getId())) {
            equipmentMaintainPo.setId(CodeTools.getCode32());
            equipmentMaintainPo.setDeleteFlag(0);
        }

        // 开启，生成对应的定时任务
        if (flag.equals(1)) {
            doStartTask(equipmentMaintainPo);
        }

        maintainMapper.save(equipmentMaintainPo);
        return Response.ok(equipmentMaintainPo);
    }

    private void doStartTask(EquipmentMaintainPo equipmentMaintainPo) {
        // 获取上次维护时间，首次默认当前保存时间
        Date lastMaintainTime = equipmentMaintainPo.getLastMaintainTime();

        if (Objects.isNull(lastMaintainTime)) {
            lastMaintainTime = new Date();
        }
        // 根据当前维护时间和时间周期计算出定时任务执行时间
        // 获取cron表达式
        String cron = getTaskTime(lastMaintainTime, equipmentMaintainPo.getMaintainPeriod());
        //String cron = "0 * * * * ? *";
        String bizId = equipmentMaintainPo.getId();
        String jobRemark = "设备定时维护：[" + equipmentMaintainPo.getId() + "]";
        xxlJobService.addSimpleJob(bizId, cron, getCurrDs(), jobRemark, getCurrUser().getAccount(), "createEquipmentMaintain", 50000);
        xxlJobService.start(bizId);
    }

    @TaskAnnotation("update")
    @Override
    public Response update(SessionFactory sessionFactory, EquipmentMaintainPo equipmentMaintainPo) {
        Assert.notNull(equipmentMaintainPo, "equipmentMaintainPo 对象不能为空！");

        EquipmentMaintainMapper maintainMapper = sessionFactory.getMapper(EquipmentMaintainMapper.class);
        Integer flag = equipmentMaintainPo.getFlag();
        if (flag.equals(0)) {
            doStopTask(equipmentMaintainPo);
        } else if (flag.equals(1)) {
            doReStartTask(equipmentMaintainPo);
        }
        int result = maintainMapper.update(equipmentMaintainPo);
        return Response.ok(result);
    }

    private void doReStartTask(EquipmentMaintainPo equipmentMaintainPo) {
        String bizId = equipmentMaintainPo.getId();
        Assert.notNull(bizId, "bizId 不能为空！");

        String cron = getTaskTime(equipmentMaintainPo.getLastMaintainTime(), equipmentMaintainPo.getMaintainPeriod());

        bizId = equipmentMaintainPo.getId();
        String jobRemark = "设备定时维护：[" + equipmentMaintainPo.getId() + "]";
        xxlJobService.update(bizId, cron, getCurrDs(), jobRemark, getCurrUser().getAccount(), "createEquipmentMaintain");        xxlJobService.start(bizId);

    }

    private String getTaskTime(Date time, Integer period) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.add(Calendar.DAY_OF_MONTH, period);
        Date cronTime = calendar.getTime();
        Date now = new Date();
        if (cronTime.before(now)) {
            // 如果暂停后启动发现下次执行的时间已经小于当前时间了，是否需要自救？
            String cron = DateUtil.format(now, "ss mm HH dd MM ? yyyy");
            return cron;
        } else {
            return DateUtil.format(cronTime, "ss mm HH dd MM ? yyyy");
        }
    }

    private Date getEndTime(Date time, Integer period) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        calendar.add(Calendar.DAY_OF_MONTH, period);
        Date endTime = calendar.getTime();
        return endTime;
    }


    private void doStopTask(EquipmentMaintainPo equipmentMaintainPo) {
        String bizId = equipmentMaintainPo.getId();
        // 删除定时任务
        xxlJobService.pause(bizId);
    }

    @TaskAnnotation("delete")
    @Override
    public Response delete(SessionFactory sessionFactory, String id) {
        Assert.notNull(id, "id 不能为空！");
        EquipmentMaintainMapper maintainMapper = sessionFactory.getMapper(EquipmentMaintainMapper.class);
        int result = maintainMapper.delete(id);
        return Response.ok(result);
    }

    @TaskAnnotation("findById")
    @Override
    public Response findById(SessionFactory sessionFactory, String id) {
        Assert.notNull(id, "id 不能为空！");
        EquipmentMaintainMapper maintainMapper = sessionFactory.getMapper(EquipmentMaintainMapper.class);
        EquipmentMaintainPo maintainPo = maintainMapper.findById(null,id);
        return Response.ok(maintainPo);
    }

    @XxlJob("createEquipmentMaintain")
    public void createEquipmentMaintain() {

        Integer jobId = (int) XxlJobHelper.getJobId();
        log.info("创建设备维护工单,jobId：" + jobId);
        Connection connection = null;

        try {
            SessionFactory sessionFactory = new SessionFactory();

            CronTaskMapper cronTaskMapper = sessionFactory.getMapper(CronTaskMapper.class);
            CronTask cronTask = cronTaskMapper.queryByXxlJobId(jobId);
            if (Objects.isNull(cronTask)) {
                log.error("创建设备维护工单失败，cronTask不存在！");
                return;
            }
            String mark = cronTask.getMark();
            sessionFactory.setDbEnv(mark);

            if (mark != null) {
                setCurrDs(mark);
            }
            // 获取数据连接对象手动提交事务
            Field field = sessionFactory.getClass().getDeclaredField("ds");
            field.setAccessible(true);
            HashMap<String, DataSource> dataSourceHashMap = (HashMap<String, DataSource>) field.get(null);
            DataSource dataSource = dataSourceHashMap.get(mark);
            connection = dataSource.getConnection();
            connection.setAutoCommit(false);

            // 获取任务的业务id
            String businessId = cronTask.getBusinessId();
            EquipmentMaintainMapper equipmentMaintainMapper = sessionFactory.getMapper(EquipmentMaintainMapper.class);
            EquipmentMaintainPo equipmentMaintainPo = equipmentMaintainMapper.findById(businessId,null);            if (Objects.isNull(equipmentMaintainPo)) {
                log.error("创建设备维护工单失败，equipmentMaintainPo不存在！");
                return;
            }
            // 生成维护工单
            MaintainDetailDto maintainPo = new MaintainDetailDto();
            BeanUtil.copyProperties(equipmentMaintainPo, maintainPo, true);

            maintainPo.setId(null);
            maintainPo.setTitle(String.format("%s自动维护保养", equipmentMaintainPo.getEquipmentName()));
            maintainPo.setSource("定时任务");
            maintainPo.setSourceId("cron_task");
            maintainPo.setStatus("DRAFT");
            //maintainPo.setCode(CodeTools.getCodeNo("WH","yyyyMM",4));
            maintainPo.setStartTime(equipmentMaintainPo.getLastMaintainTime());
            maintainPo.setEndTime(getEndTime(equipmentMaintainPo.getLastMaintainTime(), equipmentMaintainPo.getMaintainPeriod()));
            maintainPo.setDeleteFlag(0);
            maintainPo.setNeedStatus(0); // 默认不需要作业表单
            // 作业过程中的设备
            MaintainEquipmentPo maintainEquipmentPo = new MaintainEquipmentPo();
            maintainEquipmentPo.setEquipmentId(equipmentMaintainPo.getEquipmentId());
            maintainEquipmentPo.setEquipmentName(equipmentMaintainPo.getEquipmentName());

            maintainPo.setMaintainEquipmentPoList(Collections.singletonList(maintainEquipmentPo));
            // 保存维护工单
            Response<Object> response = orderFeignService.insertOrUpdate(maintainPo);
            Integer code = (Integer) JSONUtil.parseObj(response).get("code");
            if (HttpStatus.OK.value() == code) {
                log.info("设备基础维护计划下发成功，维护工单id为：[" + maintainPo.getId() + ']');

                // 工单下发成功修改计划下次执行时间
                Date now = new Date();
                String nextCron = getTaskTime(now, equipmentMaintainPo.getMaintainPeriod());
                xxlJobService.update(equipmentMaintainPo.getId(), nextCron, null, null, null, null);

                equipmentMaintainPo.setLastMaintainTime(now);
                equipmentMaintainMapper.update(equipmentMaintainPo);


                connection.commit();

                // 异步发送消息提醒
                CompletableFuture.runAsync(() -> {
                    notifyMaintain(equipmentMaintainPo, maintainPo);
                });

            } else {
                log.info("设备基础维护计划下发失败，维护工单id为：[" + maintainPo.getId() + ']');
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            try {
                if (connection != null) {
                    connection.rollback();
                }
            } catch (SQLException ex) {
                log.error(e.getMessage(), e);
            }
        }
    }

    private void notifyMaintain(EquipmentMaintainPo equipmentMaintainPo, MaintainDetailDto maintainPo) {
        String deptManage = maintainPo.getDeptManage();
        if (StrUtil.isBlank(deptManage)){
            return;
        }
        PostUserQuery postUserQuery = new PostUserQuery();
        postUserQuery.setPostIdList(Collections.singletonList("部门主管"));
        postUserQuery.setOrgIdList(Collections.singletonList(deptManage));
        Response<List<PostUserVo>> resp = systemFeignService.queryPostList(postUserQuery);
        if (HttpStatus.OK.value() == resp.getCode()) {
            List<PostUserVo> postUserVoList = resp.getData();
            if (CollectionUtils.isEmpty(postUserVoList)) {
                log.info("部门主管不存在，不发送消息！");
                return; // 没有主管，不发送消息
            }
            String content = String.format("设备[%s]的周期维护计划[%s]维护工单下发成功，请及时查看！",equipmentMaintainPo.getEquipmentName(), maintainPo.getCode());
            String handlers = postUserVoList.stream().map(PostUserVo::getUserName).collect(Collectors.joining(","));

            // 发送企业微信消息提醒
            CompletableFuture.runAsync(() -> {
                messageUtil.sendQywxText(handlers, content);
            });

        }
    }
}
